﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;

namespace Common
{
    public static partial class EnumHelper
    {
        public static string GetMyDesc<T>(this T myEnum) where T : IComparable, IFormattable, IConvertible
        {
            return GetMyDesc(typeof(T), myEnum.GetInt());
        }
        public static T GetMyEnumFromDesc<T>(string AnyDescr) where T : IComparable, IFormattable, IConvertible
        {
            //  MyDescAttribute retVal = new MyDescAttribute();
            FieldInfo[] fis = typeof(T).GetFields();
            if (fis.Length == 0)
            {
                return GetDefaultEnum<T>();
            }
            foreach (FieldInfo item in fis)
            {
                if (item.GetType().FullName == "System.Reflection.RtFieldInfo") continue;
                var arrs  = item.GetCustomAttributes(typeof(MyDescAttribute), false) ;
                if ( arrs.Length == 0 ) continue ;
                MyDescAttribute desc = arrs[0] as MyDescAttribute;
                if (desc.Desc.GetString().ToLower() == AnyDescr.ToLower()) return item.Name.ToEnum<T>();
            }
            return GetDefaultEnum<T>();
        }

        /// <summary>
        /// 按Short 来.
        /// </summary>
        /// <param name="EnumType"></param>
        /// <param name="myEnumValue"></param>
        /// <returns></returns>
        public static string GetMyDesc(Type EnumDefineType, int myEnumValue)
        {
            List<string> retVal = new List<string>();
            List<int> val = myEnumValue.ToEnumList(EnumDefineType, EnumType.Short);
            Array oriData = Enum.GetValues(EnumDefineType);

            if (val.Count > 1)
            {
                val.Remove(0);
            }
            foreach (int eachVal in val)
            {
                foreach (var item in oriData)
                {
                    if (item.GetInt() == eachVal)
                    {
                        Object[] objList = EnumDefineType.GetField(item.GetString()).GetCustomAttributes(typeof(MyDescAttribute), false);
                        if (objList.Length == 0)
                        {
                            retVal.Add(item.GetString());
                        }
                        else
                        {
                            retVal.Add(((MyDescAttribute)objList[0]).ToString());
                        }
                        break;
                    }
                }
            }

            return string.Join(" , ", retVal.ToArray());
        }

        public static T GetDefaultEnum<T>() where T : IComparable, IFormattable, IConvertible
        {
            foreach (var item in Enum.GetValues(typeof(T)))
            {
                T retVal = (T)item;
                if (retVal.GetInt() == 0) return retVal;
                else if (retVal.GetString().Equals("None", StringComparison.CurrentCultureIgnoreCase)) return retVal;
                else if (retVal.GetString().Equals("Default", StringComparison.CurrentCultureIgnoreCase)) return retVal;
            }
            return default(T);
        }
        public static T ToEnum<T>(this string EnumString, T DefautValue) where T : IComparable, IFormattable, IConvertible
        {
            if (EnumString.HasValue() == false) return DefautValue;
            string[] values = EnumString.Split(',');
            object retObj = null;
            for (int i = 0; i < values.Length; i++)
            {
                if (char.IsDigit(values[i][0]))
                {
                    retObj = (T)(object)(Convert.ToInt32(retObj) | values[i].GetInt());
                    continue;
                }
                if (Enum.IsDefined(typeof(T), values[i]) == false) continue;
                if (retObj == null)
                {
                    retObj = Enum.Parse(typeof(T), values[i]);
                    continue;
                }
                retObj = (T)(object)(Convert.ToInt32(retObj) | (int)Enum.Parse(typeof(T), values[i]));
            }
            if (retObj == null) return DefautValue;
            return (T)retObj;
        }

        public static T ToEnum<T>(this string EnumString) where T : IComparable, IFormattable, IConvertible
        {
            return ToEnum<T>(EnumString, GetDefaultEnum<T>());
        }
        public static T ToEnum<T>(this int EnumValue) where T : IComparable, IFormattable, IConvertible
        {
            return (T)(object)EnumValue;
        }

        public static List<T> GetEnumList<T>(params T[] ExceptEnum) where T : IComparable, IFormattable, IConvertible
        {
            return GetEnumList<T>(EnumType.NotZero | EnumType.Long, ExceptEnum);
        }

        /// <summary>
        /// 可优化。
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="TheEnumType"></param>
        /// <param name="ExceptEnum"></param>
        /// <returns></returns>
        public static List<T> GetEnumList<T>(EnumType TheEnumType, params T[] ExceptEnum) where T : IComparable, IFormattable, IConvertible
        {
            return ToEnumList<T>(-1, TheEnumType).Minus(ExceptEnum).ToList();
        }
        public static List<T> ToEnumList<T>(this T TheUnionEnum) where T : IComparable, IFormattable, IConvertible
        {
            return ToEnumList<T>(TheUnionEnum, EnumType.NotZero | EnumType.Long);
        }

        public static List<T> ToEnumList<T>(this T TheUnionEnum, EnumType TheEnumType) where T : IComparable, IFormattable, IConvertible
        {
            return ToEnumList<T>(TheUnionEnum.GetInt(), TheEnumType);
        }

        public static List<T> ToEnumList<T>(this int TheUnionEnum, EnumType TheEnumType) where T : IComparable, IFormattable, IConvertible
        {
            return ToEnumList(TheUnionEnum, typeof(T), TheEnumType).Select(o => (T)(object)o).ToList();
        }

        public static List<int> ToEnumList(this int TheUnionEnum, Type EnumDefineType, EnumType TheEnumType)
        {
            List<int> retVal = new List<int>();
            List<int> removeList = new List<int>();

            var fds = Enum.GetValues(EnumDefineType);

            foreach (var item in fds)
            {
                int val = item.GetInt();
                if (TheUnionEnum.Contains(val.GetInt()))
                {
                    retVal.Add(val);
                }
            }

            if (TheEnumType.Contains(EnumType.Short))
            {
                retVal.All(o =>
                    {
                        List<int> eachOne = GetEachDefine(o);

                        if (eachOne.Count > 1)
                        {
                            retVal.All(s =>
                            {
                                if (o.Contains(s)) removeList.Add(s);
                                return true;
                            });
                            removeList.Remove(o);
                        }
                        return true;
                    });
            }

            if (TheEnumType.Contains(EnumType.NotZero))
            {
                removeList.Add(0);
            }
            removeList = removeList.Distinct().ToList();

            retVal = retVal.Minus(removeList).ToList();
            return retVal;
        }


        public static bool Contains<T>(this T TheContainer, T TheOne) where T : IComparable, IFormattable, IConvertible
        {
            int con = ValueProc.GetInt(TheContainer);
            int one = ValueProc.GetInt(TheOne);
            if (con == one) return true;
            if ((con & one) == one) return true;
            return false;
        }

        public static bool IsFriendly<T>(this T TheContainer, T TheOne) where T : IComparable, IFormattable, IConvertible
        {
            return (TheContainer.GetInt() & TheOne.GetInt()) > 0;
        }

        public static List<int> GetEachDefine(int EnumValue)
        {
            EnumValue = EnumValue & int.MaxValue;
            List<int> list = new List<int>();
            int step = 0;
            while (EnumValue > 0)
            {
                int yu = EnumValue % 2;
                if (yu > 0)
                {
                    list.Add(1 << step);
                }
                EnumValue = EnumValue >> 1;
                step++;
            }
            return list;
        }
    }

}